﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Win32;
using System.IO.Ports;
using System.Threading;
using System.IO;

namespace IAP_Update
{
    public partial class frmMain : Form
    {
 #region"定义声明"
        Uart bUart = new Uart();      //对象

        bool bCheckFlag;              //CRC校验

        bool isDisableShowFlag = true;//是否是禁止接收区显示

        bool dataRcvWay = true;       //为true时，使用myserialPort_DataReceived事件接收数据，为false时使用UART_Receive函数接收数据

        bool isHexSendFlag = true;     //为true时，以十六进制发送数据
        bool isHexShowFlag = true;     //为true时，以十六进制显示接收数据

        bool isUpdate = false;
        /// <summary>
        /// 定义一个代理
        /// </summary>
        private delegate void DispMSGDelegate(string MSG);
        //定义一个队列，用于记录用户创建的线程
        //以便在窗体关闭的时候关闭所有用于创建的线程
        private List<Thread> ChaosThreadList;


        /// <summary>
        /// IAP
        /// </summary>
        public const int MAX_VALUE = 1024;           // 发送数据每次1KB
        public const string BLANK_LINE = "\r\n\r\n";
  
        int bFileLength ;                            // bin文件数据长度
        int rcvCnt;                                  // 发送数据计数
        int lastRcvCnt;                              // 记录当前发送数据计数

        //byte[] singleBuf = new byte[MAX_VALUE + 1];// 单次要发送的缓冲，发送数据缓存每次1KB加BCC异或校验
        byte[] singleBuf = new byte[MAX_VALUE];      // 单次要发送的缓冲，发送数据缓存每次1KB加BCC异或校验
        byte[,] totalBuf;                            // 总缓冲，将BIN文件大小都整成1KB的倍数

        int totalFrequency;                          // 共计发送数据的次数

        //串口接收的数据
        static Queue<string> queue = new Queue<string>();// 队列是先进先出
        Int32 cnt = 0;

        bool isStopUpgradeFlag =true;                    // 是否是停止升级，为false时停止升级
#endregion

        public frmMain()
        {
            InitializeComponent();
            // 窗体的初始化函数，初始化线程队列ChaosThreadList
            ChaosThreadList = new List<Thread>();
            // 当串口有数据收到时，启动myserialPort_DataRecieved事件函数
            Uart.oSerialPort.DataReceived += new SerialDataReceivedEventHandler(myserialPort_DataReceived);        
        }
        /**/
        /// <summary>
        /// 16进制字符串转换为二进制数组
        /// </summary>
        /// <param name="hexstring">用空格切割字符串</param>
        /// <returns>返回一个二进制字符串</returns>
        public static byte[] HexStringToBinary(string hexstring)
        {

            string[] tmpary = hexstring.Trim().Split(' ');
            byte[] buff = new byte[tmpary.Length];
            for (int i = 0; i < buff.Length; i++)
            {
                buff[i] = Convert.ToByte(tmpary[i], 16);
            }
            return buff;
        }
        /// <summary>
        /// 将一条十六进制字符串转换为ASCII
        /// </summary>
        /// <param name="hexstring">一条十六进制字符串</param>
        /// <returns>返回一条ASCII码</returns>
        public static string HexStringToASCII(string hexstring)
        {
            byte[] bt = HexStringToBinary(hexstring);
            string lin = "";
            for (int i = 0; i < bt.Length; i++)
            {
                lin = lin + bt[i] + " ";
            }

            string[] ss = lin.Trim().Split(new char[] { ' ' });
            char[] c = new char[ss.Length];
            int a;
            for (int i = 0; i < c.Length; i++)
            {
                a = Convert.ToInt32(ss[i]);
                c[i] = Convert.ToChar(a);
            }

            string b = new string(c);
            return b;
        }

        #region"方法一：从计算机注册表的特定位置读取出串口信息"
        public string[] GetComList()
        {
            RegistryKey keyCom = Registry.LocalMachine.OpenSubKey("Hardware\\DeviceMap\\SerialComm");
            string[] sSubKeys = keyCom.GetValueNames();
            string[] strArr = new string[sSubKeys.Length];
            for (int i = 0; i < sSubKeys.Length; i++)
            {
                strArr[i] = (string)keyCom.GetValue(sSubKeys[i]);
            }
            return strArr;
        }
        #endregion

        #region"方法二：利用.NET下提供的SerialPort类，读取出串口信息"
        void GetPort()
        {
            Microsoft.Win32.RegistryKey hklm = Microsoft.Win32.Registry.LocalMachine;
            Microsoft.Win32.RegistryKey software11 = hklm.OpenSubKey("HARDWARE");
            //打开"HARDWARE"子健
            Microsoft.Win32.RegistryKey software = software11.OpenSubKey("DEVICEMAP");
            Microsoft.Win32.RegistryKey sitekey = software.OpenSubKey("SERIALCOMM");
            //获取当前子健
            String[] strArr = sitekey.GetValueNames();//方法1
            //String[] strArr = System.IO.Ports.SerialPort.GetPortNames();//方法2，直接取得串口值

            //获得当前子健下面所有健组成的字符串数组
            Int32 ValueCount = sitekey.ValueCount;
            for (int i = 0; i < ValueCount; i++)
                cboCom.Items.Add(sitekey.GetValue(strArr[i]));
        }
        #endregion


        #region"定义一个函数，用于向窗体上的TextBox控件添加内容"
        /// <summary>
        /// 定义一个函数，用于向窗体上的TextBox1控件添加内容
        /// </summary>
        /// <param name="iIndex"></param>
        /// <param name="strMsg"></param>
        private void DispMsg(string strMsg)
        {
            if (this.txtReceive.InvokeRequired == false)                 
            {
                //如果调用该函数的线程和控件textBox1位于同一个线程内
                txtReceive.AppendText(strMsg.ToUpper());//ToUpper 转大写
                //txtReceive.Text+=strMsg;
            }
            else//如果调用该函数的线程和控件textBox1不在同一个线程
            {
                //通过使用Invoke的方法，让子线程告诉窗体线程来完成相应的控件操作
                DispMSGDelegate DMSGD = new DispMSGDelegate(DispMsg);
                //使用控件textBox1的Invoke方法执行DMSGD代理(其类型是DispMSGDelegate)
                this.txtReceive.Invoke(DMSGD, strMsg);
            }
        }
        #endregion  


        #region 串口配置
        //串口号
        private void cboCom_SelectedIndexChanged(object sender, EventArgs e)
        {
            bool tIsOpen;//记录当前状态

            if (Uart.oSerialPort.IsOpen)//如果串口关闭
            {
                Uart.oSerialPort.Close();
                tIsOpen = true;
            }
            else
            {
                tIsOpen = false;
            }
            //Uart.oSerialPort.PortName  = (string)cboCom.Items[cboCom.SelectedIndex];
            Uart.oSerialPort.PortName = this.cboCom.Text.Trim();
            //////////////////////////////////////////////////////////////////////////
            if (tIsOpen)//如果之前是打开则打开
            {
                Uart.oSerialPort.Open();
            }

        }

        //波特率
        private void cboBaudRate_SelectedIndexChanged(object sender, EventArgs e)
        {
            bool tIsOpen;//记录当前状态

            if (Uart.oSerialPort.IsOpen)//如果串口关闭
            {
                Uart.oSerialPort.Close();
                tIsOpen = true;
            }
            else
            {
                tIsOpen = false;
            }
            Uart.oSerialPort.BaudRate = Convert.ToInt32(this.cboBaudRate.Text.Trim());
            //////////////////////////////////////////////////////////////////////////
            if (tIsOpen)//如果之前是打开则打开
            {
                Uart.oSerialPort.Open();
            }
        }

        //数据位
        private void cboDataBits_SelectedIndexChanged(object sender, EventArgs e)
        {
            bool tIsOpen;//记录当前状态
            if (Uart.oSerialPort.IsOpen)//如果串口关闭
            {
                Uart.oSerialPort.Close();
                tIsOpen = true;
            }
            else
            {
                tIsOpen = false;
            }
            Uart.oSerialPort.DataBits = Convert.ToInt32(this.cboDataBits.Text.Trim());
            //////////////////////////////////////////////////////////////////////////
            if (tIsOpen)//如果之前是打开则打开
            {
                Uart.oSerialPort.Open();
            }
        }

        //校验位 
        private void cboParity_SelectedIndexChanged(object sender, EventArgs e)
        {
            bool tIsOpen;//记录当前状态

            if (Uart.oSerialPort.IsOpen)//如果串口关闭
            {
                Uart.oSerialPort.Close();
                tIsOpen = true;
            }
            else
            {
                tIsOpen = false;
            }
            ParitySelect(this.cboParity.Text, 0x01);
            //////////////////////////////////////////////////////////////////////////
            if (tIsOpen)//如果之前是打开则打开
            {
                Uart.oSerialPort.Open();
            }
        }

        //停止位
        private void cboStopBits_SelectedIndexChanged(object sender, EventArgs e)
        {
            bool tIsOpen;//记录当前状态
            if (Uart.oSerialPort.IsOpen)//如果串口关闭
            {
                Uart.oSerialPort.Close();
                tIsOpen = true;
            }
            else
            {
                tIsOpen = false;
            }
            StopBitsSelect(this.cboStopBits.Text, 0x01);
            //////////////////////////////////////////////////////////////////////////
            if (tIsOpen)//如果之前是打开则打开
            {
                Uart.oSerialPort.Open();
            }

        }

        /// <summary>
        /// 校验位,停止位 
        /// </summary>
        /// <param name="value"></param>
        /// <param name="flag"></param>
        private void StopBitsSelect(string value, byte flag)
        {
            switch (value)//停止位                      
            {
                case "0":
                {
                    if ((flag & 0x01) == 0x01)
                    {
                        Uart.oSerialPort.StopBits = StopBits.None;
                    }
                    if ((flag & 0x02) == 0x02)
                    {
                        this.cboStopBits.SelectedIndex = 0;
                    }
                    break;
                }
                case "1":
                {
                    if ((flag & 0x01) == 0x01)
                    {
                        Uart.oSerialPort.StopBits = StopBits.One;
                    }
                    if ((flag & 0x02) == 0x02)
                    {
                        this.cboStopBits.SelectedIndex = 1;
                    }
                    break;
                }
                case "1.5":
                {
                    if ((flag & 0x01) == 0x01)
                    {
                        Uart.oSerialPort.StopBits = StopBits.OnePointFive;
                    }
                    if ((flag & 0x02) == 0x02)
                    {
                        this.cboStopBits.SelectedIndex = 2;
                    }
                    break;
                }
                case "2":
                {
                    if ((flag & 0x01) == 0x01)
                    {
                        Uart.oSerialPort.StopBits = StopBits.Two;
                    }
                    if ((flag & 0x02) == 0x02)
                    {
                        this.cboStopBits.SelectedIndex = 3;
                    }
                    break;
                }
                default:
                {
                    MessageBox.Show("Error：参数不正确", "Error");
                    break;
                }
            }
        }
        /// <summary>
        /// 校验位
        /// </summary>
        /// <param name="value"></param>
        /// <param name="flag"></param>
        private void ParitySelect(string value, byte flag)
        {
            switch (value)
            {
                case "无校验":
                {
                    if ((flag & 0x01) == 0x01)
                    {
                        Uart.oSerialPort.Parity = Parity.None;
                    }
                    if ((flag & 0x02) == 0x02)
                    {
                        this.cboParity.SelectedIndex = 0;
                    }
                    break;
                }
                case "奇校验":
                {
                    if ((flag & 0x01) == 0x01)
                    {
                        Uart.oSerialPort.Parity = Parity.Odd;
                    }
                    if ((flag & 0x02) == 0x02)
                    {
                        this.cboParity.SelectedIndex = 1;
                    }
                    break;
                }
                case "偶校验":
                {
                    if ((flag & 0x01) == 0x01)
                    {
                        Uart.oSerialPort.Parity = Parity.Even;
                    }
                    if ((flag & 0x02) == 0x02)
                    {
                        this.cboParity.SelectedIndex = 2;
                    }
                    break;
                }
                case "Mark":
                {
                    if ((flag & 0x01) == 0x01)
                    {
                        Uart.oSerialPort.Parity = Parity.Mark;
                    }
                    if ((flag & 0x02) == 0x02)
                    {
                        this.cboParity.SelectedIndex = 3;
                    }
                    break;
                }
                case "Space":
                {
                    if ((flag & 0x01) == 0x01)
                    {
                        Uart.oSerialPort.Parity = Parity.Space;
                    }
                    if ((flag & 0x02) == 0x02)
                    {
                        this.cboParity.SelectedIndex = 4;
                    }
                    break;
                }
                default:
                {
                    MessageBox.Show("Error：参数不正确", "Error");
                    break;
                }
            }
        }
        /// <summary>
        /// 保存配置数据
        /// </summary>      
        private void SaveConfigParm()
        {
            try
            {
                string cfgINI = Application.StartupPath + IniFile.FILE_NAME;
                if (File.Exists(cfgINI))
                {
                    IniFile ini = new IniFile(cfgINI);
                    ini.IniWriteValue("Serial", "port", this.cboCom.Text.Trim());//端口
                    ini.IniWriteValue("Serial", "baudrate", this.cboBaudRate.Text.Trim());//波特率
                    ini.IniWriteValue("Serial", "databits", this.cboDataBits.Text.Trim()); //数据位
                    ini.IniWriteValue("Serial", "parity", this.cboParity.Text.Trim());//校验位
                    ini.IniWriteValue("Serial", "stopbits", this.cboStopBits.Text.Trim());//停止位

                    ini.IniWriteValue("Special", "function", "0");//特殊功能
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
            }
        }


        /// <summary>
        /// 串口打开或关闭
        /// </summary>
        private void btnOpenOrClose_Click(object sender, EventArgs e)
        {
            try
            {
                if ((Uart.oSerialPort.IsOpen) || (btnOpenOrClose.Text == "关闭串口"))//如果串口关闭
                {
                    Uart.oSerialPort.Close(); //关闭串口   
                }

                if (btnOpenOrClose.Text == "关闭串口")
                {
                    btnOpenOrClose.Text = "打开串口";
                    slSerialStatus.Text = "串口关闭";

                    btnOpenOrClose.ForeColor = Color.Black;
                    slSerialStatus.ForeColor = Color.Black;
                    //shapeComStatus.FillColor = Color.Black;
                }
                else// 打开串口
                {
                    //Uart.oSerialPort.PortName = GlobalVariables.gPort;
                    //Uart.oSerialPort.BaudRate = GlobalVariables.gBaudRate;

                    Uart.oSerialPort.Open(); //打开串口操作
                    btnOpenOrClose.Text = "关闭串口";
                    slSerialStatus.Text = cboCom.Text + "串口打开";

                    btnOpenOrClose.ForeColor = Color.Lime;
                    slSerialStatus.ForeColor = Color.Lime;
                    //shapeComStatus.FillColor = Color.Lime;

                    //保存配置参数
                    SaveConfigParm();

                    

                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("没有发现此串口或被占用" + ex.Message.ToString(), "系统信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
                //LogHelper.WriteLog("logerror", "frmMain->btnOpenOrClose_Click()" + ex.Message);
            }
        }
 #endregion 串口配置


        private void frmMain_Load(object sender, EventArgs e)
        {
            //1、动态添加串口号
            cboCom.Items.Clear();

            //方法一：
            GetPort();//读取串口号

            try
            {
                //获取配置参数
                (new GlobalMethods()).GetConfigParm();
                Uart.oSerialPort.PortName = Uart.gUartInfo.portName;//串口号
                Uart.oSerialPort.BaudRate = Uart.gUartInfo.bandRate;//波特率  
                Uart.oSerialPort.DataBits = Uart.gUartInfo.dataBits;//数据位

                this.cboCom.Text = Uart.oSerialPort.PortName;
                this.cboBaudRate.Text = Uart.oSerialPort.BaudRate.ToString();
                this.cboDataBits.Text = Uart.oSerialPort.DataBits.ToString();

                ParitySelect(Uart.gUartInfo.parity, 0x03);//校验位
                StopBitsSelect(Uart.gUartInfo.stopBits, 0x03);//停止位

                slSerialStatus.Text = "串口关闭";

                // 当串口有数据收到时，启动myserialPort_DataRecieved事件函数
                Uart.oSerialPort.DataReceived += new SerialDataReceivedEventHandler(myserialPort_DataReceived);

                txtReceive.Clear();
                txtReceive.AppendText("设备程序升级，用户操作步骤：" + BLANK_LINE + 
                    "第1步、先断开待升级的设备电源；" + BLANK_LINE +
                    "第2步、打开串口（串口配置：波特率为115200、校验位为无校验、数据位为8、停止位为1）；" + BLANK_LINE +
                    "第3步、载入待要升级的BIN文件。先请点击菜单栏上【载入】然后选择待要载入二进制BIN文件；" + BLANK_LINE +
                    "第4步、启动升级，在菜单栏中点击【升级】即设备程序升级已就绪；" + BLANK_LINE + // 显示读取的文件名及路径
                    "第5步、打开待升级的设备电源即可完成设备程序升级，详见系统提示信息；" + BLANK_LINE +
                    "提示：1、设备系统升级完成（成功）后，建议把设备断电重启；" + BLANK_LINE +
                    "      2、如果系统提示升级失败，请用户按以上步骤重做1至4遍。" + BLANK_LINE
                    );
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }                 
        }


        /// <summary>
        /// 清空接收区
        /// </summary>
        private void btnClearReceive_Click(object sender, EventArgs e)
        {

            txtReceive.Clear();
        }

        /// <summary>
        /// 清空发送区
        /// </summary>
        private void btnClearSend_Click(object sender, EventArgs e)
        {
            txtSend.Clear();
        }

        /// <summary>
        /// 窗体的关闭事件处理函数，在该事件中将之前创建的线程全部终止
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void frmMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (ChaosThreadList.Count > 0)
            {
                //编列自定义队列,将所有线程终止
                foreach (Thread tWorkingThread in ChaosThreadList)
                {
                    tWorkingThread.Abort();
                }
            }
        }


 #region 菜单栏
        ////////////////////////////////////////////////////////////////      
        /// <summary>
        /// 打开待升级的BIN文件
        /// 这部分对应窗体的载入按钮，是将BIN文件载入数组tempData，因为BIN文件字节大小不全是1KB的整数倍，
        /// 所以如果到最后还剩一些字节，再跟下位机进行比对太麻烦，所以采用化零为整的方式，把最后剩下的字节都整成1KB
        /// </summary>
        private void MenuOpenFile_Click(object sender, EventArgs e)
        {
            try
            {
               ControlsEnable(0x1F,false);
                //第一步：打开指定文件获取路径
                ofdFileLoad.Filter = "BIN文件|*.bin";
                ofdFileLoad.RestoreDirectory = true;
                ofdFileLoad.FilterIndex = 1;
                ofdFileLoad.FileName = "";

                if (ofdFileLoad.ShowDialog() == DialogResult.OK)//打开文件对话框
                {
                    string strPath = ofdFileLoad.FileName;//获取源文件的路径 

                    byte[] tempData = GlobalMethods.ReadFileToBytes(strPath);//tempData为bin文件读取缓存
                    if (tempData == null)//无数据
                    {
                        //ControlsEnable(0x1F, true);
                        return;
                    }
                    bFileLength = tempData.Length;

                    int mod = bFileLength % MAX_VALUE;
                    if (0 < mod)//余数大于0
                    {
                        totalFrequency = (int)(bFileLength / MAX_VALUE) + 1;//总发送次数  
                    }
                    else
                    {
                        totalFrequency = (int)(bFileLength / MAX_VALUE);   //总发送次数  
                    }

                    totalBuf = new byte[totalFrequency, MAX_VALUE + 1];//总缓冲

                    int currentMax = MAX_VALUE;
                    for (int i = 0; i < totalFrequency; i++)//将原bin件数据整成是1KB数据，不足的填0
                    {
                        if (i == totalFrequency - 1)
                        {
                            currentMax = mod;
                        }
                        for (int j = 0; j < currentMax; j++)//将原bin件数据整成是1KB数据，不足的填0
                        {
                            totalBuf[i, j] = tempData[i * MAX_VALUE + j];
                        }
                    }
                    progressBarFile.Minimum = 0;//'定义进度条最小值
                    progressBarFile.Maximum = totalFrequency;//定义进度条最大值
                    rcvCnt = 0;
                    txtReceive.Text += "文件导入成功，载入的文件路径为：" + strPath + BLANK_LINE;// 显示读取的文件名及路径
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
            }
            finally
            {
                ControlsEnable(0x1F, true);
            }
        }
        /// <summary>
        /// 启动或者停止升级
        /// </summary>
        private void MenuStartUpgrade_Click(object sender, EventArgs e)
        {
            bool isErr = true;
            try
            {
                ControlsEnable(0x1D, false);

                if ((!Uart.oSerialPort.IsOpen) || (btnOpenOrClose.Text == "打开串口"))//如果串口关闭
                {
                    MessageBox.Show("请先打开串口！", "系统信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    isErr = false;
                    return ;
                }
            
                if (MenuStartUpgrade.Text == "启动升级")
                {
                    MenuStartUpgrade.Text = "停止升级";
                    if (bFileLength <= 0)
                    {
                        MessageBox.Show("请先载入BIN文件！", "系统信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        isErr = false;
                        return;
                    }

                    dataRcvWay = false;//禁止使用myserialPort_DataReceived事件接收数据
                    progressBarFile.Value = 0;
                    timerProgressUpdate.Start();              
                    lastRcvCnt = 0;

                    txtReceive.Text += BLANK_LINE;
                    txtReceive.Text += "启动升级，请勿断开电源..." + BLANK_LINE;// 显示读取的文件名及路径
                }
                else
                {
                    isStopUpgradeFlag = false;//停止升级
                    txtReceive.Text += "正在执行【停止升级】操作..." + BLANK_LINE ;
                }
                ////////////////////////////////////////////////////////////////////////
                //1、发送引导码
                while (bUart.ShakeHands() == false)//等待联机
                {
                    Thread.Sleep(100);

                    if ((cnt < 100000) && (isStopUpgradeFlag ==true))
                    {
                        cnt++;
                    }
                    else
                    {
                        txtReceive.Text += "程序升级失败！" + BLANK_LINE +
                        "温馨提示： 请用户按以上设备程序升级步骤重做1至3遍。" + BLANK_LINE;
                        isErr = false;
                        return;
                    }
                }

                //2、发送文件大小以及次数
                if (!bUart.BinFileSizeFrequency(bFileLength, totalFrequency))
                {
                    txtReceive.Text += "程序升级失败！" + BLANK_LINE +
                    "温馨提示： 请用户按以上设备程序升级步骤重做1至3遍。" + BLANK_LINE;
                    isErr = false;
                    return;
                }
                //3、发送用户程序数据
                for (rcvCnt = 0; rcvCnt < totalFrequency; rcvCnt ++)
                {
                    //接收到下位机可以接收新程序请求
                    for (int i = 0; i < MAX_VALUE; i++)
                    {
                        singleBuf[i] = totalBuf[rcvCnt, i];
                    }
                    //singleBuf[MAX_VALUE] = bUart.BCC_CheckSum(singleBuf);//进行BCC异或校验
                    lastRcvCnt = rcvCnt;

                    if (!bUart.UserProgramData(singleBuf))
                    {
                        txtReceive.Text += "程序升级失败！" + BLANK_LINE +
                        "温馨提示： 请用户按以上设备程序升级步骤重做1至3遍。" + BLANK_LINE;
                        isErr = false;
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
            }
            finally
            {
                MenuStartUpgrade.Text = "启动升级";                   

                if (isErr == false)
                {
                    progressBarFile.Value = 0;
                    if (timerProgressUpdate.Enabled)
                    timerProgressUpdate.Stop();
                    rcvCnt = 0;                   
                    //OverCount = 0;
                    dataRcvWay = true;//使用myserialPort_DataReceived事件接收数据
                    ControlsEnable(0x1D, true);
                }
            }
        }

 #endregion 菜单栏

        #region"当串口有数据收到时，启动myserialPort_DataRecieved事件函数"
        private void myserialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (!dataRcvWay) return;//使用设备系统升级功能时，不能往下执行                
            try
            {
                if (isHexSendFlag)
                {
                    string strRevRet = null;
                    string strRevAscii = null;
                    string strRevTmp = null;
                    int ByteCount = Uart.oSerialPort.BytesToRead;//获取缓冲字节数
                    if (ByteCount > 0)
                    {
                        Uart.gUartInfo.rcvBuffer = new byte[ByteCount];//接收缓冲
                        Uart.oSerialPort.Read(Uart.gUartInfo.rcvBuffer, 0, ByteCount);                   
                        for (int i = 0; i < ByteCount; i++)
                        {
                            /*
                             * 方法一：
                             * 通过采用取消线程安全保护模式的方式实现的,不建议采用
                             * System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false
                             */
                            //方法二：
                            //通过使用Invoke的方法，让子线程告诉窗体线程来完成相应的控件操作
                            //if (UART.gUartInfo.rcvBuffer[i] < 0x10)
                            //    strRev += "0" + Convert.ToString(UART.gUartInfo.rcvBuffer[i], 16) + " ";
                            //else
                            //    strRev += Convert.ToString(UART.gUartInfo.rcvBuffer[i], 16) + " ";
                            strRevTmp = Convert.ToString(Uart.gUartInfo.rcvBuffer[i], 16) + " ";
                            strRevRet += strRevTmp.Length > 2 ? strRevTmp : "0" + strRevTmp;

                            strRevAscii += HexStringToASCII(strRevTmp);
                        }
                        if (string.IsNullOrEmpty(strRevRet)) return;//为空,则跳出             
                        queue.Enqueue(strRevRet);//存入队列中

                        GlobalVariables.rxCount += ByteCount;//接收数据个数
                    }
                }
                else
                {
                    string bCmdDataStr = null;//取数据
                    byte[] data = Convert.FromBase64String(Uart.oSerialPort.ReadLine());
                    bCmdDataStr = Encoding.Unicode.GetString(data);

                    if (bCmdDataStr == string.Empty) return;//为空,则跳出             
                    queue.Enqueue(bCmdDataStr);//存入队列中
                    /////////////////////////////////////
                    int len = bCmdDataStr.Length;
                    GlobalVariables.rxCount += len;//接收数据个数            
                }

            }
            catch (System.IO.IOException ex)
            {
               Console.WriteLine(ex.GetType().Name);
            }
        }
        #endregion

        /// <summary>
        ///  串口数据处理
        /// </summary>
        private void timerDataDeal_Tick(object sender, EventArgs e)
        {
            if (!dataRcvWay) return;//使用设备系统升级功能时，不能往下执行             
            //timerDataDeal.Stop();
           
            if (queue.Count > 0)//有数据
            {
                if (timerDataDeal.Interval != 10)
                    timerDataDeal.Interval = 10;//当串口数据较多时，0.01s循环              
                string tQueue = queue.Dequeue();
                //ack_pc_action(tQueue);
                //DispMsg(tQueue);
                if (isDisableShowFlag)//正常显示
                {
                    //txtReceive.Text += tqueue + BLANK_LINE;
                    if (!isHexShowFlag)  //ASCII显示
                    {
                        txtReceive.Text += HexStringToASCII(tQueue);
                        //strRevAscii
                    }
                    else
                    {
                        txtReceive.Text += tQueue;
                    }
                }
            }
            else//当没数据时
            {
                if (timerDataDeal.Interval != 100)
                    timerDataDeal.Interval = 100;//当串口无数据时，2s循环
            }
            if (isUpdate)//冗余处理
            {
                isUpdate = false ;
                GlobalVariables.rxCount = 0;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        int lastValue;//记录上一次值
        //int OverCount=0;//超时
        private void timerProgressUpdate_Tick(object sender, EventArgs e)
        {

            if (lastValue == rcvCnt) return;//如果值没变化，直接跳出
            lastValue = rcvCnt;//记录上一次值           
            ////////////////////////////////////////////////////////////////////////
            decimal result = Math.Round((decimal)(rcvCnt) / totalFrequency, 2);

            if (rcvCnt == 0)// '进度条处理
            {
                progressBarFile.Value = totalFrequency;
            }
            else
            {
                progressBarFile.Value = rcvCnt;
            }

            if (rcvCnt > 0 && rcvCnt < totalFrequency)// 在升级状态关闭所有用户操作控件
            {
                txtReceive.Text += "请勿断开电源" + " " + "升级进度为:" + (int)(result * 100) + "%" + BLANK_LINE;
            }
            else if (totalFrequency <= rcvCnt) // 升级完成后重新开放
            {
                progressBarFile.Value = 0;
                timerProgressUpdate.Stop();

                txtReceive.Text += "已完成设备程序升级" + " " + "升级进度为:" + (int)(result * 100) + "%" + BLANK_LINE;
               
                rcvCnt = 0;              
                dataRcvWay = true;//使用myserialPort_DataReceived事件接收数据
                isUpdate = true;

                ControlsEnable(0x1D, true);
            }
        }
        /// <summary>
        /// 接收区滚动显示处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtReceive_TextChanged(object sender, EventArgs e)
        {
            txtReceive.SelectionStart = txtReceive.Text.Length;
            txtReceive.ScrollToCaret();   
        }

      /// <summary>
      /// 按钮使能或失能 
      /// </summary>
      /// <param name="value"></param>
        private void ControlsEnable(byte cls ,bool value)
        {
            if ((cls & 0x01) == 0x01)//bit0
            {
                MenuOpenFile.Enabled = value;
            }
            if ((cls & 0x02) == 0x02)//bit1
            {
                MenuStartUpgrade.Enabled = value;
            }
        }

        /// <summary>
        /// 按钮
        /// </summary>
        private void btnRst_Click(object sender, EventArgs e)
        {

            try
            {
                if ((!Uart.oSerialPort.IsOpen) || (btnOpenOrClose.Text == "打开串口"))//如果串口关闭
                {
                    MessageBox.Show("请先打开串口！", "系统信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    return;
                }                
                
                txtReceive.Text += BLANK_LINE;
                txtReceive.Text += "系统复位中，请勿断开电源..." + BLANK_LINE;// 显示读取的文件名及路径

                dataRcvWay = true;//使用myserialPort_DataReceived事件接收数据

                //1、发送复位码
                bUart.RstSystem();
    
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message.ToString());
            }
        }

        private void btnHexRev_Click(object sender, EventArgs e)
        {
            if (isHexShowFlag)
            {
                isHexShowFlag = false;     //false，以ASCII显示接收数据
                btnHexRev.Text = "ASCII显示";
            }
            else
            {
                isHexShowFlag = true;     //为true时，以十六进制显示接收数据
                btnHexRev.Text = "HEX显示";
            }
        }

        private void btnHexSend_Click(object sender, EventArgs e)
        {

            if (isHexSendFlag)
            {
                isHexSendFlag = false;     //false，以ASCII显示发送数据
                btnHexSend.Text = "ASCII发送";
            }
            else
            {
                isHexSendFlag = true;     //为true时，以十六进制发送接收数据
                btnHexSend.Text = "HEX发送";
            }
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
        }
    }

}
